\chapter{Beveiliging}
\label{Beveiliging}

Het is van belang dat de code die uitgevoerd wordt correct afgeschermd wordt,
in deze sectie wordt er beschreven op welke manieren de policies omzeild kunnen worden en hoe dit kan opgelost worden.
\par
De policy wordt correct toegepast door het in de getValue() en de putValue() methodes af te dwingen. 
Dit is omdat deze methodes door de interpreter gebruikt worden bij elke JavaScript operatie. 
Zo zal de interpreter getValue() oproepen telkens het te maken heeft met een referentie naar een object, 
en zoals eerder vermeld is alles in JavaScript een referentie naar een object.
\par
Hierdoor kan men inzien dat op alle in Narcissus context uitgevoerde code, de policy afgedwongen wordt. 
De aanvallen om de policies toch nog te omzeilen kunnen we dan opdelen in 2 categorie\"en. 
Enerzijds de afgedwongen policy aanpassen, anderzijds code in Spidermonkey context laten uitvoeren.

\section{Aanpassen van policies}
Als we code zouden kunnen uitvoeren in Spidermonkey context, dan kan de policy eenvoudig aangepast worden, het Narcissus object is er beschikbaar.
Zoals gezegd hebben Spidermonkey en Narcissus ieder een eigen omgeving, maar het Narcissus object is zelf niet beschikbaar binnen de Narcissus context.
Dit is nodig omdat anders code die uitgevoerd wordt door Narcissus, de policies en ook Narcissus zelf kan aanpassen.

Het is ook belangerijk om het window.parent object te verbergen. Dit ojbect wordt gebruikt door Narcissus en houdt eigenlijk de omgeving bij van Spidermonkey,
waardoor via dit object Narcissus toch nog beschikbaar is.

\pagebreak

Deze objecten kunnen verborgen worden door een mechanisme van Narcissus te gebruiken dat hiervoor gemaakt is. Narcissus kan namelijk een blacklist
bijhouden die bepaalde objecten kan verstoppen van het geheugen van de Narcissus context. Deze blacklist werd al gebruikt om Narcissus te verstoppen, er moest
dus enkel window.parent aan de blacklist toegevoegd worden om het aanpassen van de policies onmogelijk te maken vanuit de Narcissus context.


\section{Code uitvoeren in Spidermonkey context}
Narcissus maakt gebruik van objecten in Spidermonkey om functies te kunnen uitvoeren, 
sommige van deze kunnen als resultaat hebben dat ze code uitvoeren in Spidermonkey.
Dit is enkel mogelijk wanneer er een string als code kan meegegeven worden aan zo'n functie in Spidermonkey.

\subsection{setTimeout / setInterval}
De eval()-methode kan al reeds zonder problemen gebruikt worden, 
deze is eigenlijk gewoon een variant van de Narcissus.interpreter.evaluate()-methode. 
Zoals al reeds aangegeven was door de makers van Narcissus, zijn er nog functies die een string als code kunnen interpreteren.
Met name setTimeout en setInterval, om deze code toch veilig uit te voeren moet er extra code toegevoegd worden (zie \ref{code:setTimeout}).

\medskip
\begin{lstlisting}[caption=Aangepaste setTimeout,label=code:setTimeout]
	// Prevent setTimeout from breaking out to SpiderMonkey
	setTimeout: function(code, delay) {
 		var timeoutCode = (typeof code === "string") ?
			function() { Narcissus.interpreter.evaluate(code); } :
				code;
		return setTimeout(timeoutCode, delay);
	}
\end{lstlisting}

Merk wel op dat het enkel gaat als het een string is die meegegeven kan worden, dit geldt niet voor bijvoorbeeld een callback methode. 
Daar deze callback methode zelf ook in Narcissus ge\"evalueerd wordt (E.g. XHR, zie \ref{code:XHRcallback}).

\medskip
\begin{lstlisting}[caption=XHR met callback functie,label=code:XHRcallback]
	// callback functie
	function onResponse() {
		if (xhReq.readyState != 4)  { return; }
		// do more
 	}
	var xhReq = createXMLHttpRequest();
	xhReq.open("GET","request.php", true);
	xhReq.onreadystatechange = onResponse;
	xhReq.send(null);
	...
\end{lstlisting}

\pagebreak

\subsection{Aanmaken van script element}
De DOM API laat ons toe nieuwe scripts toe te voegen (zie \ref{code:newscriptelement}). 
Zo een script element wordt pas uitgevoerd als het aan het document toegevoegd is. 
De code die het element moet uitvoeren kan op verschillende manieren bepaald worden.
Zo kan er gebruik gemaakt worden van de "text" property zoals in het voorbeeld, maar hetzelfde effect wordt verkregen door het toevoegen van een textNode als childNode van het script element.

\medskip
\begin{lstlisting}[caption=Nieuw script toevoegen aan de DOM via JavaScript,label=code:newscriptelement]
        var g = document.createElement('script');
        var s = document.getElementsByTagName('script')[0];
        g.text = "alert('via createElement script: ' + document.cookie);"
        s.parentNode.insertBefore(g, s);
\end{lstlisting}
Buiten het invoeren van code via strings kan er ook gebruik gemaakt worden van de "src" property, 
die bij het toevoegen van het script element, het bestand op de gegeven locatie gaat inladen en de inhoud ervan gaat uitvoeren als code.
Om deze scripts toch in Narcissus te laten uitvoeren herdefini\"eren we het script element lichtjes bij de creatie ervan.
Spidermonkey definieert een functie $"$onbeforescriptexecute$"$ die uitgevoerd wordt net voor het uitvoeren van de eigenlijke code.
Dit afdwingen kan handig gedaan worden dankzij de policy die nu reeds in Narcissus zit, door een extra policy hardcoded af te dwingen (zie code \ref{code:scriptelementredef} ). 

\medskip
\begin{lstlisting}[caption=createElement variant,label=code:scriptelementredef]
	ruleSet.read[document]["createElement"] = function(tagName){
				var element = document.createElement(tagName);
				element.onbeforescriptexecute = function(evt){
						try{
							if(this.src){
								evaluateUrl(this.src,JSON_active_policy);
							}
							if(this.text){
								evaluate(this.text,JSON_active_policy);
							}
						}catch(e){}
						return false;
				}
				return element;
		}
\end{lstlisting}

Onbeforescriptexecute is geen standaard property, maar zit al sinds gecko 2.0 in Firefox.
Als deze functie returnwaarde false geeft dan wordt het script niet verder uitgevoerd. 
Hiervan maken we gebruik door de eventuele src in de evaluateUrl()-methode en de eventuele text in de evaluate()-methode uit te voeren om vervolgens sowieso false terug te geven.
Hierbij is het try/catch block ook van belang, stel dat er een error wordt gegooid op het einde van het script dan zou de $"$return false$"$ niet uitgevoerd worden en kan het script alsnog in spidermonkey uitgevoerd worden.
\par
Als laatste moeten we er dan nog enkel voor zorgen dat het onbeforescriptexecute-attribuut niet meer gewijzigd kan worden. 
Dit wordt afgedwongen in de putValue()-methode, door het type te checken en het attribuut dat aangepast moet worden (zie code \ref{code:onbeforescriptblock}.
Hier werkt onze policy niet omdat er oneindig veel scripts kunnen aangemaakt worden, met elk een unieke referentie. 

\medskip
\begin{lstlisting}[caption=onbeforescriptexecute onaanpasbaar maken,label=code:onbeforescriptblock]
	function putValue(v, w, vn) {
		if (v instanceof Reference) {
			if(v.base instanceof Element && v.propertyName === "onbeforescriptexecute")
				return null;
		...
\end{lstlisting}

Hierdoor kan men de onbeforescriptexecute methode niet meer gebruiken, aangezien dit geen standaard attribuut is en niet ondersteund is in de meeste andere browsers hoeft dit niet als een minpunt aanzien worden.

\subsection{HTML injectie}
Een wederkerend probleem is het feit dat JavaScript functies aanbied die nieuwe HTML tags in de DOM kan schrijven (document.write, Element.innerHTML, ..). 
Deze zijn niet zo eenvoudig om op te lossen, Narcissus kan enkel JavaScript evalueren en het parsen van HTML is een zeer complexe operatie.
Eerst wordt er beschreven hoe dit opgelost wordt voor innerHTML, gevolgd door een vergelijking met andere functies.
\par
De property innerHTML kan gezet worden voor elke Element node in de DOM, en verwacht als waarde een string.
Als in \ref{code:innerHTMLex1} kan deze string dus bestaan uit html-tags. Hierdoor kan op verschillende manieren JavaScript uitgevoerd worden. 
Deze kunnen onder 3 methodes geclassificeerd worden, eerst worden ze kort toegelicht en verder zal er voor elk type een oplossing geboden moeten worden.

\medskip
\begin{lstlisting}[caption=Voorbeeld innerHTML met nieuwe paragraaf,label=code:innerHTMLex1]
	var div = document.createElement('div');
	div.innerHTML = "<p>nieuwe paragraaf</p>";
	document.body.appendChild(div);
\end{lstlisting}

Het eerste type is door het invoeren van script tags (zoals in \ref{code:innerHTMLex2}),
waarbij zoals bij het aanmaken van een script element, ook de text of de inhoud van een bestand in Narcissus moet ge\"evalueerd worden. 

\medskip
\begin{lstlisting}[caption=Voorbeeld innerHTML met script tag,label=code:innerHTMLex2]
	div.innerHTML = "<script>alert(document.cookie);</script>";
\end{lstlisting}

\pagebreak

Als tweede type nemen we de events die elk element kan uitvoeren (zoals in \ref{code:innerHTMLex3}). 
Hierbij heeft een image element de property onload, waarbij de value als string uitgevoerd wordt wanneer de afbeelding geladen is. 
Merk op dat er geen misbruik kan gemaakt worden via deze events in JavaScript, de events verwachten een stuk code en geen string, zoals de callback functie van XHR.

\medskip
\begin{lstlisting}[caption=Voorbeeld innerHTML met element met onload event,label=code:innerHTMLex3]
	div.innerHTML = "<img src='my_image.gif' onload='alert(document.cookie);' />";
\end{lstlisting}

Als derde en laatste zijn er nog enkele uitzonderingen, deze categorie kan gezien worden als de XSS (Cross Site Scripting) categorie.
Bepaalde properties laten het ook toe om javascript uit te voeren, 
zoals in \ref{code:innerHTMLex4} zal er bij het klikken op het element, het script uitgevoerd worden.

\medskip
\begin{lstlisting}[caption=Voorbeeld innerHTML met javascript in href,label=code:innerHTMLex4]
	div.innerHTML = "<a href='javascript:alert(document.cookie);' >Klik hier</a>";
\end{lstlisting}

\subsubsection{innerHTML}

Het eenvoudige stuk is er voor zorgen dat de waarde niet aan de originele innerHTML toegekend wordt. 
Dit kan opnieuw gedaan worden zoals "onbeforescriptexecute", een extra if die nagaat of het attribuut innerHTML is.
En in plaats van aan innerHTML toe te kennen een eigen functie uit te voeren.
\par
Voor het moeilijke stuk, het interpreteren van de HTML, zijn er meerdere problemen op te lossen. 
Er is geen HTML parser beschikbaar, een XML parser werkt enkel voor XHTML stricte syntax en het is niet mogelijk JavaScript tijdelijk af te zetten. Wel is het mogelijk om de innerHTML te zetten van een element dat niet aan een document vasthangt. 
Op deze manier wordt de string ook geparset en omgezet naar DOM nodes, zonder dat script tags uitgevoerd worden. 
Helaas geldt dit niet voor events, e.g. onload van een img-tag wordt toch uitgevoerd wanneer een afbeelding geladen is.
Om dit te vermijden wordt er eerst een reguliere expressie uitgevoerd op de hele string, die alle events (attributen die beginnen met on), hernoemt waardoor deze niet meteen uitgevoerd worden maar toch nog opgevraagd kunnen worden nadat ze geparset zijn.

\medskip
\begin{lstlisting}[caption=Reguliere expressie die events vervangt,label=code:regexEvents]
	// met elem als ingegeven html-string
	elem = elem.replace(/ (on)(\w+) *=/ig, ' $1$2narc=');
\end{lstlisting}

\pagebreak

De reguliere expressie in \ref{code:regexEvents} is gekozen omdat events altijd beginnen met on (e.g. onload, onblur, ..), 
gevolgd door een = teken waartussen zich spaties kunnen bevinden. 
Deze is bewust zeer los gekozen, om te vermijden dat deze expressie omzeild kan worden, 
het is bijvoorbeeld niet nodig dat er quotes gebruikt worden na het = teken om ge\"interpreteerd te worden. 
Het nadeel is dat er tekst ongewenst aangepast kan worden (E.g. $<p>$ one = een$</p>$ "). Dit wordt later opgelost.

\medskip
\begin{lstlisting}[caption=Gebruik nieuwe div als HTML parser, label=code:innerHTMLparse]
	var div = document.createElement("div");
	div.innerHTML = elem;
\end{lstlisting}

De childNodes van de div kunnen dan geappend worden aan het Element waar oorspronkelijk de innerHTML van gezet werd. 
Voor dat dit gedaan wordt moeten alle nodes eerst veilig gemaakt worden. Volgens de 3 types eerder beschreven. 
\par
Voor het eerste type wordt er gekeken of de node een script element is, 
indien dit het geval is slagen we het script (src en/of text) op in een Object. 
Het Object heeft een functie execute, dat net als bij onbeforescriptexecute, de code in Narcissus uitvoert. 
Dit Object wordt aan een lijst toegevoegd. 
De index die het krijgt in deze lijst zal gebruikt worden om vanuit SpiderMonkey context dit script uit te voeren. 
Het oorspronkelijke script wordt vervangen door een nieuw script dat de nieuwe methode evaluateScript(scriptId) gebruikt.
EvaluateScript neemt het script op de gegeven index en voert het uit. 
Op deze manier wordt ook de correcte volgorde van uitvoeren behouden. 

\medskip
\begin{lstlisting}[caption=Script element in Narcissus laten uitvoeren, label=code:type1scripts]
var rWrongProps = / (on)(\w+)narc=/ig;
 if ( nodeName( script, "script" ) && (!script.type || /\/(java|ecma)script/i.test( script.type )) ) {
	var scriptId = narcScripts.length;
	if(script.text && rWrongProps.test(script.text))
		script.text = script.text.replace(rWrongProps," $1$2=");
	narcScripts[scriptId] = new NarcScript(script);
	var newScript = elem.ownerDocument.createElement("script");
	newScript.appendChild(elem.ownerDocument.createTextNode("Narcissus.interpreter.evaluateScript("+scriptId+");"));
	elem.parentNode.replaceChild(newScript,elem);
	elem = newScript;
}
...
// Object dat als parameter een script element nodig heeft en dit gebruikt om uit te voeren in Narcissus
var NarcScript = function(script){
	this.src = script.src;
	this.text = script.text;
	this.execute = function(){
		if(this.src)
			evaluateUrl(this.src, JSON_active_policy);		
		else if(this.text)
			evaluate(this.text, JSON_active_policy);
	}	
}
\end{lstlisting}

\begin{lstlisting}[caption=De evaluateScript methode, label=code:evaluateScript]
	var narcScripts = [];
	function evaluateScript(id){
		if(typeof id === "number" && narcScripts[id]){
			narcScripts[id].execute();
		}
	}
\end{lstlisting}

Merk ook op dat, indien het een inline script is, er nog een reguliere expressie op uitgevoerd wordt. Dit wordt gedaan omdat het mogelijk is dat de reguliere expressie die events aanpast, ook de scripts aanpast.

\begin{lstlisting}[caption=Script dat foutief zou worden aangepast]
var onload = "test"; // wordt var onloadnarc= "test";
alert(onload); // blijft alert(onload); 
\end{lstlisting}

\subsubsection{Events}

Het 2de type dat beschermd moet worden zijn de events. 
Deze zijn zoals eerder beschreven hernoemd via een reguliere expressie. 
Alle attributen van elk element worden afgegaan en met een nieuwe reguliere expressie wordt nagegaan of de attribuut een event is.
Indien dit zo is, wordt de eigenlijke actie eruit gefilterd (e.g. onloadnarc = load).
Voor deze kan dan een eventlistener toegevoegd worden aan het element. Hoe dit juist gebeurd wordt later uitgelegd. 
De attributen waarvoor een eventlistener is toegevoegd worden verwijderd van het element. Deze zijn nu vervangen. 
Als laatste wordt er voor elke childNode gecheckt of er een textNode tussenzit.
Op elke textNode wordt dan nog een reguliere expressie uitgevoerd, die er voor moet zorgen dat de text die eventueel is aangepast door de eerste expressie, terug vervangen wordt door de oorspronkelijke text.

\medskip
\begin{lstlisting}[caption=Events in Narcissus laten uitvoeren, label=code:type2scripts]
	// elem is het element dat gecheckt wordt
	var to_remove = [];
	var rEventPropNarc = /on(\w+)narc/ig; // regex die attributen checkt op events
	for(j in elem.attributes){
		let attr = elem.attributes[j].name;
			if(rEventPropNarc.test(attr)){ // check of het een event is
				let action = attr.replace(rEventPropNarc,'$1'); // filter de eigenlijke actie
				(function() {
					let code = elem.getAttribute(attr);
					attachNarcissusEvent(action,code,elem);
				})();
				to_remove[to_remove.length]= attr;
			}
		}
		for(rAttr in to_remove)
			elem.removeAttribute(to_remove[rAttr]); // verwijder attributen
		.. check op textNodes..
\end{lstlisting}

\pagebreak

\subsubsection{XSS aanvallen}

Voor het 3de type, de XSS manier, hebben we de XSS cheat sheet\cite{XSScheatsheet} afgegaan, 
en gekeken welke aanvallen kunnen uitgevoerd worden op deze implementatie. Dus enkel aanvallen die in Firefox werken, 
kunnen van toepassing zijn op het prototype. De 2 overblijvende aanvallen waren het misbruik van src en href attribuut (zoals in \ref{code:innerHTMLex4}). 
Wanneer men deze in SpiderMonkey context test merkt men geen verschil tussen href met onclick en src met onload. 
Deze observatie laat toe dezelfde methode als type 2 te gebruiken mbhv een extra if.

\medskip
\begin{lstlisting}[caption=Speciale attributen met JavaScript in Narcissus laten uitvoeren, label=code:type3scripts]
	var rJSexec = /javascript:/ig;
	var risky = {'src' : 'load', 'href' : 'click'};
	...
	else if(risky[attr] && rJSexec.test(elem.getAttribute(attr))){ // catch other xss attacks
		(function() {
			let code = elem.getAttribute(attr).replace(rJSexec,"");
			attachNarcissusEvent(risky[attr],code,elem);
		})();
		elem.setAttribute(attr, "javascript:");
		to_remove[to_remove.length]= attr;
	}
\end{lstlisting}

Als de waarde van het attribuut $"$javascript:$"$ bevat, wordt het verwijderd en wordt het verder afgehandeld als bij type 2. Bepaald door de lijst $"$risky$"$. 
Belangrijk is dat dit in tegenstelling tot bij events, in JavaScript ook misbruik kan gemaakt worden van deze methode (vb zie \ref{code:vulnerXss}).
De check die reeds bestaat in putValue moet dus worden aangevuld met deze check.
Het principe is hetzelfde als in \ref{code:type3scripts} en wordt daardoor niet opnieuw beschreven.

\medskip
\begin{lstlisting}[caption=javascript uitvoeren via href, label=code:vulnerXss]
	var a = document.createElement('a');
	a.href="javascript:alert(document.cookie);";
	document.body.appendChild(a);
\end{lstlisting}

Als laatste deel moeten de functies nog gekoppeld worden aan de juiste events van het juiste element.
Code in een element heeft een eigen scope, zo is this niet het window object, maar het element zelf.
Een paragraaf kan bijvoorbeeld onzichtbaar gemaakt worden door er op te klikken (zie \ref{code:hideParag}).

\medskip
\begin{lstlisting}[caption=verbergen van een paragraaf via onclick, label=code:hideParag]
	<p onclick="this.style.visibility='hidden';">verberg mij</p>
\end{lstlisting}

\pagebreak

Als we gewoon de evaluate() methode gebruiken dan zou dit dus niet het gewenste effect geven.
Er is nood aan een oplossing die zowel $"$style$"$ als $"$this.style$"$ herkent als eigenschappen van het element waarop de eventlistener uitgevoerd wordt. Hiervoor gebruiken we de getValue() en putvalue() methodes opnieuw. 
De eventlistener die we toevoegen, zet een tijdelijke variabele in Narcissus voor het uitvoeren van de eigenlijke code.
Dit is mogelijk omdat de eventlistener zelf in Spidermonkey context uitvoert en daardoor aan het Narcissus object kan. 
Als tijdelijke variabele gebruiken we dan het element, in getValue() moet dan enkel gecheckt worden of het element al dan niet undefined is,
en indien het bestaat, kan dat element als this gebruikt worden.
 
\medskip
\begin{lstlisting}[caption=eventlistener toevoegen aan element, label=code:attachevent]
	var eventHook = {element : undefined}
	var attachNarcissusEvent = function(action, code, element){
		let f = '(function() { ' + code + '})();';
		let fun = function(evnt){
			Narcissus.interpreter.eventHook.element = element; // hook to execute in the right context
			Narcissus.interpreter.global.event = evnt;
			Narcissus.interpreter.evaluate(f);
			Narcissus.interpreter.global.event = undefined;
			Narcissus.interpreter.eventHook.element = undefined;
		};
		element.addEventListener(action, fun, false);
	}
\end{lstlisting}

\medskip
\begin{lstlisting}[caption=Extra code in getValue om in de juiste scope uit te voeren, label=code:eventHook]
	if(eventHook.element !== undefined && v.base === global && eventHook.element.hasOwnProperty(v.propertyName))
		v.base = eventHook.element; // hook for events
	...
	return v.base[v.propertyName];
\end{lstlisting}

Als laatste mogelijkheid is er nog de iframe die zowel via JavaScript als via HTML kan ingevoegd worden. 
Door een link mee geven in het src attribuut, kan een externe webpagina geladen worden. 
Deze kan zijn eigen origine hebben, de html kan dan ook niet zomaar gedownload worden via XHR aangezien het van een ander domein afkomstig is. 
Door deze problemen is dit niet vanzelfsprekend om iframes te ondersteunen, we opteren dan ook om iframes niet toe te laten.
\par
Het toepassen van deze methode met innerHTML, op een functie als document.write brengt nog enkele extra problemen met zich mee. 
Bij document.write kan de html in stukken geschreven worden, en nog altijd als een element ge\"interpreteerd worden bvb. 
$document.write('<p>');document.write('test');document.write('</p>');$ zal als een paragraaf verschijnen in de DOM. 
Met de huidige methode zou men 2 paragrafen met een textnode ertussen krijgen. 
Om dit op te lossen checken we of de string die geschreven moet worden geldige xml is, en indien dit zo is, 
worden de elementen die aangemaakt worden door de functie aan de body gehangen. Dit is een eerder na\"ieve methode, 
en zal nooit foute xhtml schrijven naar de DOM, maar volstaat voor dit prototype. 
De prioriteit binnen deze thesis is gegaan naar het testen en beveiligen van Narcissus.
